package com.xialuo.study.agent;

import com.xialuo.study.tools.ChartGenerator;
import com.xialuo.study.tools.DataAnalyzer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * ReAct模式的代理，实现思考-行动-观察的循环执行流程
 */
@Component
public class ReActAgent {
    private static final Logger logger = LoggerFactory.getLogger(ReActAgent.class);
    private final ChatClient chatClient;
    private final DataAnalyzer dataAnalyzer;
    private final ChartGenerator chartGenerator;

    private static final int MAX_STEPS = 10; // 设置适当的最大步骤数

    private static final String SYSTEM_PROMPT = """
            你是一个专业的数据分析执行专家，负责按照计划执行数据分析任务。你需要按照ReAct（思考-行动-观察）模式工作：先思考分析策略，然后执行具体行动，最后观察结果并决定下一步。
            
            # 可用工具
            
            1. analyzeData - 读取和分析CSV数据
               - 参数：{"dataPath": "数据文件路径"}
               - 返回：解析后的表格数据（JSON格式）
               - 用途：获取原始数据，进行初步分析
            
            2. generateChart - 生成数据可视化图表
               - 参数：{"chartType": "图表类型(line/bar)", "xAxis": "X轴列名", "yAxis": "Y轴列名", "csvData": "csv格式的数据"}
               - 返回：生成的图表文件路径
               - 用途：将数据可视化，便于发现模式和趋势
            
            # 执行指南
            
            1. 分析当前步骤的目标和需求
            2. 根据需要调用适当的工具获取和处理数据
            3. 对数据进行深入分析，提取关键信息和洞见
            4. 记录分析过程和发现，确保可以追踪你的思路
            5. 在完成任务后，提供清晰、结构化的分析结果
            
            # 注意事项
            
            1. 必须先使用analyzeData获取数据，不要假设数据内容
            2. 确保传入工具的参数格式正确
            3. 图表生成前必须有数据分析作为基础（有效的参数和类型，注意csv格式）
            4. 分析结果应该包含数据发现、趋势分析和业务洞见
            5. 任务完成后必须明确标记结束，使用以下格式之一：
               - "分析结果: [你的结果]"
               - "总结: [你的总结]"
               - "结论: [你的结论]"
            6. 确保只有在任务真正完成时才使用上述标记，否则将继续对话
            
            每个步骤执行完成后，请确认是否完成了当前任务。如果完成，必须使用上述标记格式提供最终结果。
            """;

    public ReActAgent(ChatClient chatClient, DataAnalyzer dataAnalyzer,
                     ChartGenerator chartGenerator) {
        this.chatClient = chatClient;
        this.dataAnalyzer = dataAnalyzer;
        this.chartGenerator = chartGenerator;
    }

    /**
     * 执行分析任务
     * @param plan 整体分析计划
     * @param step 当前执行的步骤
     * @param dataPath 数据文件路径
     * @return 执行结果
     */
    public String executeAnalysis(String plan, String step, String dataPath) {
        // 初始化对话消息
        List<Message> messages = new ArrayList<>();
        messages.add(new SystemMessage(SYSTEM_PROMPT));
        messages.add(new UserMessage(formatUserPrompt(plan, step, dataPath)));

        // 执行多轮对话
        return executeConversation(messages);
    }

    /**
     * 格式化用户提示
     */
    private String formatUserPrompt(String plan, String step, String dataPath) {
        return String.format("""
                # 分析任务
                
                ## 整体计划
                %s
                
                ## 当前步骤
                %s
                
                ## 数据文件
                %s
                
                请按照ReAct模式（思考-行动-观察）执行当前步骤的数据分析任务。
                确保分析结果专业、深入且提供有价值的见解。
                当步骤完成后，请以"分析结果:"、"总结:"或"结论:"开头明确标记完成。
                """, plan, step, dataPath);
    }

    /**
     * 执行多轮对话
     */
    private String executeConversation(List<Message> messages) {
        int steps = 0;
        StringBuilder conversationLog = new StringBuilder();

        try {
            while (steps < MAX_STEPS) {
                logger.info("执行对话步骤 {}/{}", steps + 1, MAX_STEPS);

                // 调用模型，自动执行工具调用
                var response = chatClient.prompt()
                    .messages(messages)
                    .tools(dataAnalyzer, chartGenerator)
                    .call();

                String content = response.content();
                if (content == null || content.isEmpty()) {
                    logger.warn("收到空响应，跳过处理");
                    continue;
                }
                logger.debug("响应内容:" + content);

                conversationLog.append("步骤 ").append(steps + 1).append(":\n").append(content).append("\n\n");

                // 将响应添加到消息历史
                messages.add(new AssistantMessage(content));

                // 检查是否任务完成
                if (isTaskComplete(content)) {
                    logger.info("任务完成，提取最终结果");
                    return extractFinalAnswer(content);
                } else if (steps < MAX_STEPS - 1) {
                    // 如果还没达到最大步骤且任务未完成，添加一个提示消息让AI明确是否已完成
                    messages.add(new UserMessage("任务是否已完成？如果已完成，请以「分析结果:」或「总结:」或「结论:」开头提供最终结果。如果未完成，请继续分析。"));
                }

                steps++;
            }

            logger.warn("达到最大步骤数 ({}), 返回当前结果", MAX_STEPS);
            return "达到最大步骤数限制。\n\n 当前执行状态:\n\n" + conversationLog.toString();

        } catch (Exception e) {
            logger.error("执行分析时发生错误", e);
            return "执行失败: " + e.getMessage() + "\n\n已执行内容:\n" + conversationLog.toString();
        }
    }

    /**
     * 检查任务是否完成
     */
    private boolean isTaskComplete(String response) {
        if (response == null || response.isEmpty()) {
            return false;
        }

        // 更严格的标记检测模式 - 检查是否包含完成标记
        Pattern completionPattern = Pattern.compile("^(?:分析结果|总结|结论|Analysis Result|Summary|Conclusion)[:：]",
                                                   Pattern.MULTILINE);

        Matcher matcher = completionPattern.matcher(response);
        boolean hasCompletionMarker = matcher.find();

        if (hasCompletionMarker) {
            logger.info("检测到任务完成标记");
            return true;
        }

        // 检查是否包含明确的完成指示
        boolean hasCompletionIndication =
            response.contains("任务已完成") ||
            response.contains("分析完成") ||
            response.contains("步骤完成") ||
            response.contains("分析结果如下") ||
            response.contains("分析总结如下");

        if (hasCompletionIndication) {
            logger.info("检测到完成指示语");
            return true;
        }

        return false;
    }

    /**
     * 从响应中提取最终答案
     */
    private String extractFinalAnswer(String response) {
        // 尝试提取结论或总结部分
        Pattern[] patterns = {
            Pattern.compile("(?:分析结果|总结|结论|Analysis Result|Summary|Conclusion)[:：]\\s*(.*)", Pattern.DOTALL),
            Pattern.compile("(?:任务已完成|分析完成).*?[。.!]\\s*(.*)", Pattern.DOTALL)
        };

        for (Pattern pattern : patterns) {
            Matcher matcher = pattern.matcher(response);
            if (matcher.find()) {
                return matcher.group(1).trim();
            }
        }

        // 如果找不到特定标记，提取最后一部分作为结果
        String[] paragraphs = response.split("\n\n");
        if (paragraphs.length > 0) {
            // 返回最后一个非空段落
            for (int i = paragraphs.length - 1; i >= 0; i--) {
                if (!paragraphs[i].trim().isEmpty()) {
                    return paragraphs[i].trim();
                }
            }
        }

        // 如果所有尝试都失败，返回整个响应
        return response.trim();
    }
}
